package com.smsc.headend.task.engine.handler.impl.collection.builder;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.SystemClock;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.smsc.headend.common.enums.DeviceType;
import com.smsc.headend.module.asset.entity.Dcu;
import com.smsc.headend.module.asset.entity.Meter;
import com.smsc.headend.module.asset.entity.PlcMeterStatus;
import com.smsc.headend.module.protocol.DeviceData;
import com.smsc.headend.module.protocol.cosem.bo.CosemData;
import com.smsc.headend.module.report.entity.LogPlcNetworkTopology;
import com.smsc.headend.module.task.dto.AtomicTask;
import com.smsc.headend.module.task.dto.Task;
import com.smsc.headend.task.engine.service.CosemXmlService;
import com.smsc.headend.task.engine.service.FeignAssetManagementService;
import com.smsc.headend.task.engine.service.RdScheduleReadParamValueService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Slf4j
@Service
public class PlcNetworkTopoInfoHandler implements ScheduleReadBuilder {
    @Autowired
    FeignAssetManagementService assetManagementService;

    @Autowired
    CosemXmlService cosemXmlService;

    @Autowired
    RdScheduleReadParamValueService rdScheduleReadParamValueService;

    @Autowired
    KafkaTemplate kafkaTemplate;

    @Override
    public void handleScheduleReadResult(Task task, AtomicTask atomicTask, DeviceData deviceData, String actionResult, Boolean dcuDataItemFlag,Map<String, Object> param) {

        Map<String, Object> map = JSONUtil.toBean(task.getParamJson(), Map.class);
//        String referValue = String.valueOf(map.get("referValue"));
////        String descrb = String.valueOf(map.get("descrb"));
        String dcuIdStr = String.valueOf(map.get("dcuId"));
//        String dataItemIdStr = String.valueOf(map.get("dataItemId"));
//        String paramIdStr = (String) map.get("paramId");
//        Long paramId = Long.valueOf(paramIdStr);

        CosemData cosemData = (CosemData) deviceData;
        List<LogPlcNetworkTopology> saveList = translateNetWorkTopologyInformationCosem(cosemData, dcuIdStr);
        if (CollUtil.isNotEmpty(saveList)) {
            log.info("save the plcNetworkTopo Info size{}", saveList.size());
            assetManagementService.savePlcNetworkRecord(saveList);
        } else {
            log.info("the plcNetworkTopoInfo is empty");
        }
    }

    public List<LogPlcNetworkTopology> translateNetWorkTopologyInformationCosem(CosemData cosemData, String dcuIdStr) {
        List<LogPlcNetworkTopology> topologyList = new ArrayList<>();
        if (null == cosemData || CollUtil.isEmpty(cosemData.getChild())) {
            return null;
        }
        Long tvUpdate = SystemClock.now() / 1000;
        String dcuNodeLongAddr = "";
        Dcu dcu =  assetManagementService.getDcuById(Convert.toLong(dcuIdStr));
        if (CollUtil.isNotEmpty(cosemData.getChild())) {
            // 第一个structure结构中 node_long_address特殊处理为该dcu的资产号
            CosemData rootStrCosemData = cosemData.getChildAt(0).getChildAt(0);
            Object value = cosemXmlService.getData(rootStrCosemData.getType(), rootStrCosemData.getValue());
            dcuNodeLongAddr = value.toString();
        }
        for (int i = 0; i < cosemData.getChild().size(); i++) {
            CosemData structData = cosemData.getChildAt(i);
            LogPlcNetworkTopology logPlcNetworkTopology = new LogPlcNetworkTopology();
            for (int index = 0; index < structData.getChild().size(); index++) {
                CosemData data = structData.getChild().get(index);
                Object value = cosemXmlService.getData(data.getType(), data.getValue());
                switch (index) {
                    case 0:
                        if (i == 0) {
                            logPlcNetworkTopology.setNodeLongAddr(dcu.getMfgSn());
                            logPlcNetworkTopology.setMeterId(dcu.getDcuId());
                        } else {
                            String meterSerialNo = value.toString();
                            logPlcNetworkTopology.setNodeLongAddr(meterSerialNo);
                            if (StrUtil.isNotEmpty(meterSerialNo)) {
                                Meter meter = assetManagementService.getMeterByMfgSn(meterSerialNo);
                                if (null != meter) {
                                    logPlcNetworkTopology.setMeterId(meter.getMeterId());
                                    logPlcNetworkTopology.setOnlineStatus(getPlcOnlineStatus(meter.getMeterId()));
                                } else {
                                    logPlcNetworkTopology.setDescrb("Meter Not Exist");
                                }
                            }
                        }
                        break;
                    case 1:
                        logPlcNetworkTopology.setNodeShortAddr(value.toString());
                        break;
                    case 2:
                        String parentLongAddr = value.toString();
                        if (i == 0) {
                            logPlcNetworkTopology.setIsRootNode(1);
                            logPlcNetworkTopology.setParentId(dcu.getDcuId());
                            logPlcNetworkTopology.setParentDeviceType(DeviceType.DCU.getId());
                        } else {
                            if (StrUtil.equalsIgnoreCase(parentLongAddr, dcuNodeLongAddr)) {
                                parentLongAddr = dcu.getMfgSn();
                                logPlcNetworkTopology.setParentLongAddr(parentLongAddr);
                                logPlcNetworkTopology.setParentId(dcu.getDcuId());
                                logPlcNetworkTopology.setParentDeviceType(DeviceType.DCU.getId());
                            } else {
                                Meter meter = assetManagementService.getMeterByMfgSn(parentLongAddr);
                                if (null != meter) {
                                    logPlcNetworkTopology.setParentId(meter.getMeterId());
                                    logPlcNetworkTopology.setParentDeviceType(DeviceType.METER.getId());
                                }
                                logPlcNetworkTopology.setParentLongAddr(parentLongAddr);
                            }
                        }
                        break;
                    case 3:
                        long signalLength = 0L;
                        if (value != null) {
                            if (NumberUtil.isNumber((String) value)) {
                                signalLength = Long.parseLong((String) value);
                            }
                        }
                        logPlcNetworkTopology.setSignalStrength(signalLength);
                        break;
                    case 4:
                        logPlcNetworkTopology.setNetworkStatus(Integer.parseInt(data.getValue()));
                        break;
                    case 5:
                        Float longitude = (Float)value;
                        logPlcNetworkTopology.setLongitude(longitude);
                        break;
                    case 6:
                        Float latitude = (Float)value;
                        logPlcNetworkTopology.setLatitude(latitude);
                        break;
                    case 7:
                        logPlcNetworkTopology.setPhase(Integer.parseInt(data.getValue()));
                        break;
                    default:
                        break;

                }
            }
            logPlcNetworkTopology.setTvUpdate(tvUpdate);
            logPlcNetworkTopology.setSrc(LogPlcNetworkTopology.TopologySrc.Auto.getCode());
            topologyList.add(logPlcNetworkTopology);
        };
        return topologyList;
    }

    private Integer getPlcOnlineStatus(Long meterId) {
        try {
            PlcMeterStatus plcMeterStatus = assetManagementService.getPlcMeterStatus(meterId);
            if (plcMeterStatus != null) {
                return plcMeterStatus.getStatus();
            }
        } catch (Exception e) {
            log.info("get plcMeterStatus error {}", e.getMessage());
        }
        return null;
    }
}
